package com.wut.clock.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.github.pagehelper.PageHelper;
import com.wut.clock.aop.log.BusinessStatus;
import com.wut.clock.common.api.CommonPage;
import com.wut.clock.common.exception.Asserts;
import com.wut.clock.common.service.RedisService;
import com.wut.clock.common.util.AddressUtil;
import com.wut.clock.common.util.ClockUtil;
import com.wut.clock.common.util.IpUtil;
import com.wut.clock.common.util.ServletUtil;
import com.wut.clock.config.MailClient;
import com.wut.clock.dto.admin.ShiroSysUser;
import com.wut.clock.dto.admin.UserParams;
import com.wut.clock.entity.SysLoginLog;
import com.wut.clock.entity.SysRole;
import com.wut.clock.entity.SysUser;
import com.wut.clock.entity.SysUserRole;
import com.wut.clock.mapper.SysLoginLogMapper;
import com.wut.clock.mapper.SysRoleMapper;
import com.wut.clock.mapper.SysUserMapper;
import com.wut.clock.mapper.SysUserRoleMapper;
import com.wut.clock.service.IHomeService;
import com.wut.clock.service.IRoleService;
import com.wut.clock.service.IUserService;
import com.wut.clock.util.Md5Util;
import com.wut.clock.util.ShiroUtil;
import com.wut.clock.vo.admin.LoginVo;
import com.wut.clock.vo.admin.UserInfoVo;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Date;
import java.util.List;
import java.util.Random;

/**
 * @author ZYH
 * @unit D9Lab
 * @description 用户服务实现类
 * @date 2022/5/29 16:59
 */
@Service
@RequiredArgsConstructor
@Slf4j
public class UserServiceImpl implements IUserService {

    private final SysUserMapper userMapper;

    private final SysUserRoleMapper userRoleMapper;

    private final RedisService  redisService;

    private final MailClient mailClient;

    private final SysLoginLogMapper loginLogMapper;

    private final IHomeService homeService;

    private final SysRoleMapper roleMapper;


    @Override
    public int insertOneUser(UserParams userParams) {
        // 校验参数
        SysUser username = userMapper.selectOne(new QueryWrapper<SysUser>().eq("username", userParams.getUsername()));
        SysUser email = userMapper.selectOne(new QueryWrapper<SysUser>().eq("email", userParams.getEmail()));
        if(username != null) Asserts.fail("用户名已被占用");
        if(email != null) Asserts.fail("邮箱已被注册");
        // 插入
        SysUser user = new SysUser();
        BeanUtils.copyProperties(userParams,user);
        user.setPassword(Md5Util.encrypt(userParams.getPassword()));
        return userMapper.insert(user);
    }

    @Override
    public int updateOneUser(UserParams userParams) {
        // 校验参数
        SysUser username = userMapper.selectOne(new QueryWrapper<SysUser>().eq("username", userParams.getUsername()));
        SysUser email = userMapper.selectOne(new QueryWrapper<SysUser>().eq("email", userParams.getEmail()));
        log.info("username={}",username);
        log.info("email={}",email);
        if (username!=null){
            if(!userParams.getId().equals(username.getId())) Asserts.fail("用户名已被占用");
        }
        if (email!=null){
            if(!userParams.getId().equals(email.getId())) Asserts.fail("邮箱已被注册");
        }
        // 修改
        SysUser user = new SysUser();
        BeanUtils.copyProperties(userParams,user);
        return userMapper.updateById(user);
    }

    @Override
    public List<SysUser> getUserList(String username, String nickName, String email, String phone, Integer pageNum, Integer pageSize) {
        PageHelper.startPage(pageNum,pageSize);
        log.info("用户传的pageNum={},pageSize={}",pageNum,pageSize);
        List<SysUser> userList = userMapper.getUserList(username,nickName,email,phone);
        return userList;
    }

    @Override
    public boolean sendRegisterMail(String type, String email) {
        String key = type +email;
        if("注册用户".equals(type)){
            SysUser findUserMail = userMapper.selectOne(new QueryWrapper<SysUser>().eq("email", email));
            if(findUserMail != null) Asserts.fail("该邮箱已经被注册!");
        }
        if(redisService.get(key) != null) Asserts.fail("验证码已经存在，请检查邮箱！");
        // 生成一个4位的随机注册码
        String code = ClockUtil.generateUuid().substring(0, 4);
        mailClient.sendMail(email,type,"请使用以下验证码: "+code+" ,3分钟之内有效!");
        // 设置成3分钟
        redisService.set(key,code,180);
        return true;
    }

    @Override
    public int registerUser(String username, String password, String confirmPassword, String email, String code) {
        // 后端判断用户是否已经存在以及邮箱是否已经注册过
        SysUser findUsername = userMapper.selectOne(new QueryWrapper<SysUser>().eq("username", username));
        if(findUsername != null) Asserts.fail("用户已经存在");
        SysUser findUserMail = userMapper.selectOne(new QueryWrapper<SysUser>().eq("email", email));
        if(findUserMail != null) Asserts.fail("该邮箱已经被注册");
        // 注册用户
        SysUser user = new SysUser();
        user.setUsername(username);
        user.setEmail(email);
        // 需要将密码加密
        user.setPassword(Md5Util.encrypt(password));
        // 给用户头像和昵称赋予初值
        user.setNickname("ClockUser"+ClockUtil.generateUuid().substring(0,3));
        //https://himg.bdimg.com/sys/portrait/hotitem/wildkid/1-67
        user.setAvatar("https://himg.bdimg.com/sys/portrait/hotitem/wildkid/"+new Random().nextInt(68) +"t.png");
        // 从 redis 中获取验证码
        String key = "注册用户" + email;
        String emailCode = redisService.get(key).toString();
        if(StringUtils.isBlank(emailCode)) Asserts.fail("验证码不存在或者已经失效，请检查邮箱是否正确或重新获取验证码");
        if(!code.equals(emailCode)) Asserts.fail("您输入的验证码错误，请重新验证");
        if(!password.equals(confirmPassword)) Asserts.fail("两次输入的密码不一致,请检查后再次输入");
        return userMapper.insert(user);
    }

    @Override
    public int forgetPassword(String email, String code, String password, String confirmPassword) {
        SysUser user = userMapper.selectOne(new QueryWrapper<SysUser>().eq("email", email));
        if(user == null) Asserts.fail("用户不存在,请检验邮箱是否正确");
        String key = "忘记密码" + email;
        String emailCode = redisService.get(key).toString();
        if(StringUtils.isBlank(emailCode)) Asserts.fail("验证码不存在或者已经失效，请检查邮箱是否正确或重新获取验证码");
        if(!code.equals(emailCode)) Asserts.fail("验证码错误，请查看邮箱");
        if(!password.equals(confirmPassword)) Asserts.fail("两次输入的密码不一致");
        user.setPassword(Md5Util.encrypt(password));
        return userMapper.updateById(user);
    }

    @Override
    public LoginVo login(String username, String password) {
        UsernamePasswordToken token = new UsernamePasswordToken(username,password);
        Subject subject = SecurityUtils.getSubject();
        //做一个登录日志
        SysLoginLog loginLog = new SysLoginLog();
        loginLog.setUserName(username);
        // 请求的地址
        String ip = IpUtil.getIpAddr(ServletUtil.getRequest());
        loginLog.setIpaddr(ip);
        String address = AddressUtil.getRealAddressByIP(ip);
        loginLog.setLoginLocation(address);
        loginLog.setLoginTime(new Date());
        try {
            subject.login(token);
        } catch (Exception e) {
            loginLog.setStatus(BusinessStatus.FAIL.ordinal());
            SysUser getUserName = userMapper.selectOne(new QueryWrapper<SysUser>().eq("username", username));
            if(getUserName==null){
                loginLog.setMsg("登录失败，用户名"+username+"不存在");
            }else {
                loginLog.setMsg("登录失败，用户名与密码不匹配");
            }
            // 处理登录日志事件
            loginLogMapper.insert(loginLog);
            throw e;
        }
        ShiroSysUser shiroSysUser = (ShiroSysUser) subject.getPrincipal();
        homeService.recordDAU(shiroSysUser.getUserId());
        loginLog.setStatus(BusinessStatus.SUCCESS.ordinal());
        loginLog.setMsg("登录成功");
        // 处理登录日志事件
        loginLogMapper.insert(loginLog);
        LoginVo loginVo = new LoginVo();
        loginVo.setToken(subject.getSession().getId());
        loginVo.setUserId(shiroSysUser.getUserId());
        loginVo.setUsername(shiroSysUser.getUsername());
        loginVo.setNickName(userMapper.selectById(shiroSysUser.getUserId()).getNickname());
        return loginVo;
    }

    @Transactional
    @Override
    public int assignRole2User(Integer userId, Integer roleId) {
        //分配之前先清空角色
        userRoleMapper.delete(new QueryWrapper<SysUserRole>().eq("user_id",userId));
        SysUserRole userRole = new SysUserRole();
        userRole.setUserId(userId);
        userRole.setRoleId(roleId);
        return userRoleMapper.insert(userRole);
    }

    @Transactional
    @Override
    public int deleteOneUser(Integer userId) {
        // 删除用户与角色关联
        userRoleMapper.delete(new QueryWrapper<SysUserRole>().eq("user_id",userId));
        return userMapper.deleteById(userId);
    }

    @Override
    public UserInfoVo getUserInfo() {
        UserInfoVo userInfoVo = new UserInfoVo();
        Integer userId = ShiroUtil.getUserId();
        SysUser user = userMapper.selectById(userId);
        BeanUtils.copyProperties(user,userInfoVo);
        Integer roleId = userRoleMapper.selectOne(Wrappers.<SysUserRole>lambdaQuery().eq(SysUserRole::getUserId, userId)).getRoleId();
        SysRole role = roleMapper.selectOne(Wrappers.<SysRole>lambdaQuery().eq(SysRole::getId, roleId));
        userInfoVo.setRoleName(role.getName());
        userInfoVo.setRoleNickname(role.getNickname());
        userInfoVo.setUserId(userId);
        return userInfoVo;
    }
}
